package com.senmo.video.view;

import android.content.Context;
import android.graphics.PointF;
import android.opengl.GLSurfaceView;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;

import com.senmo.video.jni.FrameData;
import com.senmo.video.jni.JNI;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 *
 */
public class GLVideoView extends GLSurfaceView {

    public static final String TAG = "SenMoGLFrame";

    private static final int BUFFER_SIZE = 4 * 256 * 1024;

    /**
     * 获取数据失败，已超过COUNT_GET_DATA_FAILED帧没有获得数据
     */
    public final static int CODE_GETDATA_ERROR = 1001;
    /**
     * 正在获取数据中，（一直获取到的无效数据）
     */
    public final static int CODE_GETDATA_LOADING = 1002;
    public final static int CODE_GETDATA_SUCCESS = 1003;

    private final static int SEND_LISTENER_FAILED_GAP = 20;
    /**
     * 当连续无效数据达到此值，则代表断开
     */
    private final static int COUNT_GET_DATA_FAILED = 300;

    private ExecutorService mExecutor = Executors.newSingleThreadExecutor();

    /**
     * 连续请求失败次数
     */
    private int mGetDataFailedCount = 0;
    private int mLastSendFailed = 0;
    private FrameData mFrameData;

    private volatile boolean islock = true;
    private GLFrameRenderer mGLFRenderer;

    private Timer mTimer;

    private surfaceMeidaTask mTimerTask;
    private boolean isVideoConnect = false;


    private ScaleGestureDetector mScaleDetector;

    // 事件的四种类型
    private static final int NONE = 0;
    private static final int DRAG = 1;
    private static final int ZOOM = 2;
    private static final int CLICK = 10;
    int mode = NONE;
    //双击的时间的间隔
    private static final long DOUBLE_PRESS_INTERVAL = 600;
    private static final long LONG_PRESS_INTERVAL = 2 * 1000;


    private long mActionDownTime;
    private OnLongClickListener onLongClickListener;

    private PointF last = new PointF();
    private PointF mid = new PointF();
    private PointF start = new PointF();
    /**
     * 最大最小随访比例
     */
    private float minScale = 1f;
    private float maxScale = 4f;
    private float saveScale = 1f;
    private float oldDist = 1f;

    private PointF lastDelta = new PointF(0, 0);
    private float velocity = 0;
    private long lastPressTime = 0, lastDragTime = 0;

    private OnClickListener onClickListener;

    public GLVideoView(Context context) {
        super(context);
        init(context);
    }

    public GLVideoView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context){
        setEGLContextClientVersion(2);
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        mGLFRenderer = new GLFrameRenderer(this);
        setRenderer(mGLFRenderer);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mScaleDetector.onTouchEvent(event);
        PointF curr = new PointF(event.getX(), event.getY());
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                last.set(event.getX(), event.getY());
                start.set(last);
                mode = DRAG;
                mActionDownTime = System.currentTimeMillis();
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                oldDist = spacing(event);
                if (oldDist > 10f) {
                    midPoint(mid, event);
                    mode = ZOOM;
                }
                break;

            case MotionEvent.ACTION_UP:{

                mGLFRenderer.pan(0, 0);
                mode = NONE;
                int xDiff = (int) Math.abs(event.getX() - start.x);
                int yDiff = (int) Math.abs(event.getY() - start.y);

                if (xDiff < CLICK && yDiff < CLICK) {
                    long pressTime = System.currentTimeMillis();
                    // 确认是否是双击
                    if (pressTime - lastPressTime <= DOUBLE_PRESS_INTERVAL) {
                        mTimerHandler.removeMessages(0);
                        mGLFRenderer.pan(0,0);
                        lastDelta.set(0, 0);
                        if (saveScale == 1) {
                            saveScale = 2;
                        } else {
                            saveScale = 1;
                            mGLFRenderer.pan(0,0);
                        }
                        lastPressTime = 0;
                        mGLFRenderer.setZoom(saveScale);
                    } else {
                        lastPressTime = pressTime;
                        mTimerHandler.sendEmptyMessageDelayed(0, 600);
                    }
                }
                break;
            }
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                velocity = 0;
                break;
            case MotionEvent.ACTION_MOVE:{
                if (isLongPressed(start, event, mActionDownTime, System.currentTimeMillis())
                        && onLongClickListener != null) {
                    mActionDownTime = System.currentTimeMillis();
                    onLongClickListener.onLongClick(GLVideoView.this);
                }

                if (mode == DRAG) {
                    int xDiff = (int)(curr.x - last.x );
                    int yDiff = (int)(curr.y - last.y );
                    mGLFRenderer.pan(xDiff, -yDiff);
                    last.set(curr.x, curr.y);
                }
                break;
            }
        }
        return true;
    }

    /**
     * 判断是否是长按
     */
    private boolean isLongPressed(PointF start, MotionEvent event,
                                  long lastDownTime, long thisEventTime) {
        int xDiff = (int) Math.abs(event.getX() - start.x);
        int yDiff = (int) Math.abs(event.getY() - start.y);
        long intervalTime = thisEventTime - lastDownTime;
        if (xDiff <= 10 && yDiff <= 10 && intervalTime >= LONG_PRESS_INTERVAL) {
            return true;
        }
        return false;
    }

    Handler mTimerHandler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            if (onClickListener != null)
                onClickListener.onClick(GLVideoView.this);
        }
    };

    @Override
    public void setOnClickListener(OnClickListener l) {
        this.onClickListener = l;
    }


    @Override
    public void setOnLongClickListener(OnLongClickListener onLongClickListener) {
        this.onLongClickListener = onLongClickListener;
    }

    /**
     * 得到两个手指之间的空间
     */
    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return (float) Math.sqrt(x * x + y * y);
    }

    /**
     * 计算两个手指的中间点
     */
    private void midPoint(PointF point, MotionEvent event) {
        // ...
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            mode = ZOOM;
            return true;
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            //缩放比例获取流程
            //1、一次调用只能放大或缩小原来的0.05倍
            //2、实际缩放比例等于，上次缩放比例*这次缩放比例
            //3、限制最大，最小的缩放比例；
            float mScaleFactor = (float) Math.min(
                    Math.max(.95f, detector.getScaleFactor()), 1.05);
            saveScale *= mScaleFactor;
            if (saveScale > maxScale) {
                saveScale = maxScale;
            } else if (saveScale < minScale) {
                saveScale = minScale;
            }

            mGLFRenderer.setZoom(saveScale);
            invalidate();
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
            super.onScaleEnd(detector);
        }
    }

    public float getCurrentScale(){
        return saveScale;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        setRenderMode(RENDERMODE_WHEN_DIRTY);
    }

    private float mCurrentScale = 1 ;

    public void startPlay(String videoUrl) {
        isVideoConnect = false;
        mTimer = new Timer();
        islock = true;
        int handle = JNI.connect(videoUrl);
        mFrameData = new FrameData(handle, BUFFER_SIZE);
        mTimerTask = new surfaceMeidaTask();
        mTimerTask.setDisConnect(false);
        mTimer.schedule(mTimerTask, 0, 30);
    }

    public void stopPlay() {
        Log.d(TAG, "VideoView, stop play");
        islock = false;
        isVideoConnect = false;
        stopTime();
        mGetDataFailedCount = 0;
        mLastSendFailed = 0;

        resumeZoom();
    }

    public void resumeZoom(){
        mGLFRenderer.setZoom(1);
        mGLFRenderer.pan(0,0);
        lastDelta.set(0, 0);
    }

    private void stopTime(){
        if (mTimer != null) {
            mTimerTask.setDisConnect(true);
            try {
                Thread.sleep(60);
            } catch (InterruptedException e){
            }
            stopTimer();
        }
    }
    private void stopTimer(){
        if(mTimerTask != null){

            mTimerTask.cancel();
            mTimerTask = null;
        }
        if(mTimer != null){
            mTimer.purge();
            mTimer.cancel();
            mTimer = null;
        }

        JNI.disconnect(mFrameData.handle);
    }


    private synchronized boolean getMediaDataBitmap(){

        if(!islock){
            return false;
        }
        if(!isVideoConnect){

            int status = JNI.getConnectResult(mFrameData.handle);
            if (connectResultListener != null) {
                connectResultListener.getConnectResultCode(status);
            }

            switch (status) {
                case 0:
                    isVideoConnect = true;
                    System.out.println("播放视频 连接成功时间 = " + System.currentTimeMillis());
                    return getMediaData();
                case 1:
                    break;
                case 2:
                    break;
                case 3:
                    break;

                default:
                    break;
            }
            return false;
        }
        return getMediaData();
    }

    /***
     * 获取视频数据，并进行绘图
     */
    private boolean getMediaData(){
        if (mFrameData.data == null) {
            return false;
        }
        int handle = mFrameData.handle;
        GLFrameRenderer renderer = mGLFRenderer;

        FrameData frame = JNI.getMediaData(mFrameData);
        int error = frame.errorCode;
        if (error == 1) {
            frame = JNI.getMediaData(handle, frame.buffer_size + 1024);
        }
        Log.d("liuxu", "11111, frame: " + frame);
        if (!frame.valid) {
            return false;
        }
        if (error != 0) {
            if (getMediaDataListener != null) {
                getMediaDataListener.getMediaDataCode(error);
            }
            return false;
        }

        renderer.update((int) frame.width, (int) frame.height, frame.yLen, frame.uLen, frame.vLen);

//        if(shotScreen && !TextUtils.isEmpty(shotScreenSaveKey)){
//            shotScreen = false;
//                    new Thread(new Runnable() {
//                        @Override
//                        public void run() {
//                            final String path = FileUtils.saveScreenShotRawData(
//                                    shotScreenSaveKey, GLFrameSurface.this.yuv_data,
//                                    ylen, ulen, vlen,
//                                    width, height, ystride, uvstride);
//                            if (!TextUtils.isEmpty(path) && listener != null) {
//                                listener.shotScreenResult(path);
//                            }
//                        }
//                    }).start();
//        }

        renderer.updateBuffer(
                frame.data, (int) frame.width, (int) frame.height,
                frame.yStride, frame.uvStride, frame.yLen, frame.uLen, frame.vLen);
        return true;

    }

    /**
     * 视频连接结果监听
     */
    public interface ConnectResultListener{
        public void getConnectResultCode(int resultCode);
    }


    /**
     * 数据流量监控
     */
    public interface FlowRateListener{
        public void getFlowRate(float deviceRate, float clientRate);
    }

    public FlowRateListener flowRateListener;

    public void setFlowRateListener(FlowRateListener listener){
        flowRateListener = listener;
    }
    /**
     * 获取视频数据的监听
     */
    public interface GetMediaDataListener{
        public void getMediaDataCode(int resultCode);
    }

    private ConnectResultListener connectResultListener;
    private GetMediaDataListener getMediaDataListener;
    public void setConnectResultListener(ConnectResultListener listener){
        this.connectResultListener = listener;
    }
    public void setGetMediaDataListener(GetMediaDataListener listener){
        this.getMediaDataListener = listener;
    }

    /**
     * 获得数据并绘图的定时器任务
     */
    class surfaceMeidaTask extends TimerTask{
        private boolean disConnect = false;
        public synchronized void setDisConnect(boolean disConnect){
            this.disConnect = disConnect;
        }
        @Override
        public synchronized void run() {

            if (disConnect) {
                JNI.disconnect(mFrameData.handle);
                return;
            }
            if (!islock) {
                return;
            }

            if(mGetDataFailedCount >= COUNT_GET_DATA_FAILED){
                stopPlay();

                mGetDataFailedCount = 0;
                if(getMediaDataListener != null){
                    getMediaDataListener.getMediaDataCode(CODE_GETDATA_ERROR);
                }
                return;
            }
            if(getMediaDataBitmap()){//获取并OPENGL绘图
                mGetDataFailedCount = 0;
                mLastSendFailed = 0;
                if(getMediaDataListener != null){
                    getMediaDataListener.getMediaDataCode(CODE_GETDATA_SUCCESS);
                }
            }else{
                if(isVideoConnect){
                    //对获得无效帧的处理
                    if((mGetDataFailedCount - mLastSendFailed) >= SEND_LISTENER_FAILED_GAP){
                        if(getMediaDataListener != null){
                            getMediaDataListener.getMediaDataCode(CODE_GETDATA_LOADING);
                            mLastSendFailed = mGetDataFailedCount;
                        }
                    }
                    if(mGetDataFailedCount > COUNT_GET_DATA_FAILED){
                        if(getMediaDataListener != null){
                            getMediaDataListener.getMediaDataCode(CODE_GETDATA_ERROR);
                        }
                    }
                    mGetDataFailedCount++;
                }
            }
        }
    }


    private boolean shotScreen = false;
    private String shotScreenSaveKey = null;

    public void shotScreen(String key){
        shotScreen = true;
        shotScreenSaveKey = key;
    }

    private SurfaceShotScreenListener listener;

    public void setSurfaceShotListener(SurfaceShotScreenListener listener){
        this.listener = listener;
    }

    public interface SurfaceShotScreenListener{
        public void shotScreenResult(String rawDataPath);
    }

}


